<?php

namespace common\logics\trade;

use Yii;
use yii\db\Exception;
use common\models\trade\Trade;
use common\models\trade\TradeOrder;
use common\models\user\UserAccount;
use common\models\user\UserAccountLog;

/**
 * 取消交易逻辑操作模型
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class CancelTradeHandleLogic extends \common\base\Model {

    /**
     * @var string 外部商户订单号 
     */
    public $bizno;

    /**
     * @var string 订单取消原因 
     */
    public $reason;

    /**
     * @var Trade[] 外部商户订单号关联下的所有交易（未完成状态）
     */
    private $_trades = [];

    /**
     * @inheritdoc
     */
    public function rules() {
        return [
            [['bizno', 'reason'], 'required'],
            [['bizno', 'reason'], 'string'],
            ['bizno', 'validateBizno'],
        ];
    }

    /**
     * 校验外部商户号信息，查询所有未完成状态交易
     * @param string $attribute
     */
    public function validateBizno($attribute) {
        if ($this->hasErrors()) {
            return;
        }
        $this->_trades = Trade::findByBizno($this->$attribute)->andWhere([
            'status' => [
                Trade::STATUS_DEFAULT,
                Trade::STATUS_WAITPAY
            ]
        ])->all();
    }

    /**
     * 取消交易
     * @inheritdoc
     */
    public function cancel() {
        if (!$this->validate()) {
            return false;
        }
        $trades = $this->_trades;
        if (empty($trades)) {
            return true;
        }
        $transaction = Yii::$app->db->beginTransaction();
        try {
            foreach ($trades as $trade) {
                Yii::error($trade->attributes);
                if ($trade->status !== Trade::STATUS_DEFAULT && $trade->status !== Trade::STATUS_WAITPAY) {
                    throw new Exception('当前交易状态已变更，禁止执行交易自动取消操作！');
                }
                $this->cancelTrade($trade, $this->reason);
            }
            $transaction->commit();
        } catch (Exception $e) {
            $transaction->rollBack();
            $this->addError('bizno', $e->getMessage());
            return false;
        }
        Yii::error('取消完成');
        return true;
    }

    /**
     * 取消交易
     * @param Trade $trade
     * @outputBuffering $msg
     * @param string $prefixMessage
     * @return boolean
     */
    protected function cancelTrade($trade, $prefixMessage = null) {
        if ($prefixMessage) {
            $prefixMessage = '取消交易';
        }
        $account = $trade->userAccount;
        Yii::error($account->attributes);
        //未付款或者待支付并且订单已过期则取消当前交易等操作
        //保证交易金额一致
        $tradeAmount = $trade->getOrders()->sum('pay*balance*status');
        Yii::error([
            'tradeAmount' => $tradeAmount
        ]);
        if ($tradeAmount > 0 && !empty($trade->paymentOrder)) {
            //查询当前交易中存在的已支付的交易订单
            //有需要退款的交易订单
            foreach ($trade->paymentOrder as $tradeOrder) {
                Yii::error([
                    'tradeOrder attributes' => $tradeOrder->attributes
                ]);
                $condition = [
                    'trade_id' => $tradeOrder->trade_id,
                    'original_no' => $tradeOrder->original_no,
                    'paymode' => $tradeOrder->paymode,
                    'pay_type' => $tradeOrder->pay_type,
                    'currency' => $tradeOrder->currency,
                    'pay' => $tradeOrder->pay,
                    'balance' => TradeOrder::BALANCE_REFUND,
                ];
                $query = TradeOrder::find()->andWhere($condition);
                if ($query->exists()) {
                    continue;
                }
                $refundOrder = new TradeOrder();
                $refundOrder->setAttributes($condition);
                if (!$refundOrder->save()) {
                    throw new Exception('退款交易订单申请创建失败！');
                }
                $refundOrder->recordLog($prefixMessage, '取消交易时同步创建退款订单');
                if ($refundOrder->getIsInnerPaymode()) {
                    //退积分
                    $this->refundCredit($refundOrder, $account, $prefixMessage);
                }
            }
            //再次查询确认
            $tradeAmount = $trade->getOrders()->sum('pay*status*balance');
        }
        if ($tradeAmount == 0) {
            $markMessage = '系统自动关闭当前交易';
            $trade->status = Trade::STATUS_CLOSED;
        } else {
            $markMessage = '系统自动取消当前交易';
            $trade->status = Trade::STATUS_CENCELED;
        }
        if (!$trade->save()) {
            throw new Exception('交易保存失败！');
        }
        $trade->recordLog($prefixMessage, $markMessage);
    }

    /**
     * 账户积分退款
     * @param TradeOrder $refundOrder
     * @param UserAccount $account
     * @param string $prefixMessage
     * @return void
     * @throws Exception
     */
    protected function refundCredit($refundOrder, $account, $prefixMessage) {
        if (!$account) {
            return;
        }
        $points = $refundOrder->pay * 10;
        //回滚账户积分
        $account->setPoints($points, UserAccount::USEAGE_SHOP_REFUND);
        if (!$account->save()) {
            throw new Exception('账户积分回滚失败！');
        }
        $trade = $refundOrder->trade;
        $mark = '[' . $prefixMessage . ']系统自动取消订单同步积分退款:' . $trade->subject;
        $creditLog = $account->recordLog(UserAccountLog::CHANGE_TYPE_SHOP_REFUND, $points, 'trade_order', $refundOrder->id, $mark);
        //回滚成功修改退还订单
        $refundOrder->pay_time = time();
        $refundOrder->status = TradeOrder::STATUS_SUCCESS;
        $refundOrder->pay_no = $creditLog->getUnquieId();
        if (!$refundOrder->save()) {
            throw new Exception('退款积分通知保存时失败！');
        }
    }

}
